﻿namespace Blaze.ConfigExporters
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using Aspose.Cells;
    using ConfigExportTool;
    using ConfigExportTool.Readers;
    using Configs;

    /// <summary>
    /// 多语言导出。
    /// </summary>
    public class TranslationExporter : ExporterBase
    {
        private class Line
        {
            public readonly Dictionary<string, string> Pairs = new Dictionary<string, string>();
            public string Id { get; set; }

            public Cell IdCell { get; set; }
        }

        /// <summary>
        /// 导出客户端配置。
        /// </summary>
        protected override void ExportForClient()
        {
            foreach (var db in mDBs)
                ExportToClient(db, "i18n/" + db.Id);
        }

        /// <summary>
        /// 导出服务器配置。
        /// </summary>
        protected override void ExportForServer()
        {
            foreach (var db in mDBs)
                ExportToServer(db, "i18n/" + db.Id);
        }

        protected override void Initialize()
        {
            var dir = Path.Combine(Environment.CurrentDirectory, "../../Configs/Translation");
            foreach (var path in Directory.GetFiles(dir))
            {
                if (Path.GetFileName(path).StartsWith("~$"))
                    continue;
                var workbook = new Workbook(path);
                readLines(workbook);
            }
            validateDuplication();
            setupDBs();
        }

        private Line readLine(Cell beginCell, string[] headers)
        {
            var reader = new ByOffsetReader(beginCell).AsByColumn();
            if (reader.IsEmpty)
                return null;
            var ret = new Line
            {
                Id = reader.ReadString(),
                IdCell = beginCell
            };
            for (var i = 0; i < headers.Length; i++)
            {
                var languageId = headers[i];
                var content = reader.ReadString();
                ret.Pairs.Add(languageId, content);
            }
            return ret;
        }

        private void readLines(Workbook workbook)
        {
            //读取表头
            var reader = new ByOffsetReader(workbook.Worksheets[0].Cells[0, 1]).AsByColumn();
            var headerList = new List<string>();
            while (!reader.IsEmpty)
                headerList.Add(reader.ReadString());
            var headers = headerList.ToArray();

            //读取表格
            reader = new ByOffsetReader(workbook.Worksheets[0].Cells[1, 0]).AsByRow();
            while (!reader.IsEmpty)
            {
                var line = readLine(reader.Current, headers);
                mLines.Add(line);
                reader.Skip();
            }
        }

        private void setupDBs()
        {
            var query = from line in mLines
                from pair in line.Pairs
                group new LanguageDB.Item
                {
                    Id = line.Id,
                    Value = line.Pairs[pair.Key],
                } by pair.Key
                into itemGroup
                select new LanguageDB
                {
                    Id = itemGroup.Key,
                    Items = itemGroup.ToArray(),
                };
            mDBs = query.ToArray();
        }

        private void validateDuplication()
        {
            //校验重复语言配置项
            var query = from line in mLines
                group line by line.Id
                into idGroup
                where idGroup.Count() > 1
                select idGroup;
            var duplicatedIdGroups = query.ToArray();
            if (duplicatedIdGroups.Length > 0)
            {
                var exception = new DuplicatedTranslationException();
                foreach (var g in duplicatedIdGroups)
                {
                    foreach (var line in g)
                        exception.Add(line.IdCell);
                }
                throw exception;
            }
        }

        private LanguageDB[] mDBs;

        private readonly List<Line> mLines = new List<Line>();
    }
}